<?php
namespace App\Services;

use Illuminate\Http\Client\RequestException;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class WebThreeService
{
    private static function makeSignature(string $message) : string
    {
        $secretKey = config('services.okx.secret');

        $signature = hash_hmac('sha256', $message, $secretKey, true);

        $sign = base64_encode($signature);

        return $sign;
    }

    private static function handleRequest(string $method, string $path, array $data = []) : array
    {
        $url = config('services.okx.url') . $path;

        $timestamp = Carbon::now('UTC')->format('Y-m-d\TH:i:s.v\Z');

        $message = $timestamp . $method . $path;

        if(!empty($data)) {
            if($method == "GET") {
                $message .= '?'.urldecode(http_build_query($data));
            } else {
                $message .= json_encode($data);
            }
        }

        $headers = [
            'OK-ACCESS-KEY'        => config('services.okx.key'),
            'OK-ACCESS-PASSPHRASE' => config('services.okx.passphrase'),
            'OK-ACCESS-TIMESTAMP'  => $timestamp,
            'OK-ACCESS-SIGN'       => self::makeSignature($message),
            'OK-ACCESS-PROJECT'    => config('services.okx.project')
        ];

        if(env('APP_ENV') == 'local') {
            $options = [
                'proxy' => 'http://127.0.0.1:10809'
            ];
        } else {
            $options = [];
        }

        try {
            $client = Http::timeout(9)
                -> withHeaders($headers)
                -> withOptions($options)
                -> throw()
                -> accept('application/json');

            if($method == "GET") {
                $response = $client -> get($url, $data);
            } else {
                $response = $client -> post($url, $data);
            }

            return $response->json();
        } catch(RequestException $e) {
            Log::channel('okx_api')->error('Fail', [
                'request' => [
                    'url'     => $url,
                    'method'  => $method,
                    'headers' => $headers,
                    'body'    => $data
                ],
                'response' => [
                    'code'    => $e->getCode(),
                    'message' => $e->getMessage()
                ]
            ]);

            return [
                'code'    => $e->getCode(),
                'msg'     => $e->getMessage(),
                'data'    => []
            ];
        }
    }

    public static function getSupportedChains() : array
    {
        $path = "/api/v5/wallet/chain/supported-chains";

        $res = self::handleRequest("GET", $path);

        return $res;
    }
    public static function createWalletAccount(array $addresses = []) : array
    {
        $path = "/api/v5/wallet/account/create-wallet-account";

        $data = [
            "addresses" => $addresses
        ];

        $res = self::handleRequest("POST", $path, $data);

        return $res;
    }
    public static function updateWalletAccount(array $data) : array
    {
        $path = "/api/v5/wallet/account/update-wallet-account";

        $res = self::handleRequest("POST", $path, $data);

        return $res;
    }
    public static function deleteWalletAccount(string $account_id) : array
    {
        $path = "/api/v5/wallet/account/delete-account";

        $data = [
            "accountId" => $account_id
        ];

        $res = self::handleRequest("POST", $path, $data);

        return $res;
    }
    public static function queryWalletAccount(array $data) : array
    {
        $path = "/api/v5/wallet/account/account-detail";

        $res = self::handleRequest("GET", $path, $data);

        return $res;
    }
    public static function validateAddress(string $chainIndex, string $address)
    {
        $path = "/api/v5/wallet/pre-transaction/validate-address";

        $data = [
            "chainIndex" => $chainIndex,
            "address"    => $address
        ];

        $res = self::handleRequest("GET", $path, $data);

        return $res;
    }
    public static function getAllBalances(string $accountId) : array
    {
        $path = "/api/v5/wallet/asset/total-value";

        $data = [
            "accountId" => $accountId
        ];

        $res = self::handleRequest("GET", $path, $data);

        return $res;
    }
    public static function getRate() : string
    {
        if(Cache::has('usd_rate')) {
            return Cache::get('usd_rate');
        }
        $path = "/api/v5/market/exchange-rate";
        $res = self::handleRequest("GET", $path);
        if($res['code'] == 0) {
            $usd = $res['data'][0]['usdCny'];
            Cache::put('usd_rate', $usd, 60 * 5);
        } else {
            $usd = 7;
        }

        return $usd;
    }
    public static function getMarketTickers(string $instType) : array
    {
        $path = "/api/v5/market/tickers";

        $data = [
            "instType" => $instType
        ];

        $res = self::handleRequest("GET", $path, $data);

        return $res;
    }
    public static function getInstruments(string $instType) : array
    {
        $path = "/api/v5/public/instruments";

        $data = [
            "instType" => $instType
        ];

        $res = self::handleRequest("GET", $path, $data);

        return $res;
    }
    public static function getMarketCandles(string $instId, string $bar, string $after, int $limit) : array
    {
        $path = "/api/v5/market/candles";

        $data = [
            "instId"    => $instId,
            "bar"       => $bar,
            "after"     => $after,
            "limit"     => $limit,
        ];

        $res = self::handleRequest("GET", $path, $data);

        return $res;
    }
}
